#pragma once

#include <AVUISize3D.h>

namespace AVUI {

/// <summary>Represents a 3-D rectangle: for example, a cube. </summary>
class Rect3D
{
public:
    DECLARE_VALUE_ELEMENT(Rect3D);

#pragma region Public Methods

    /// <summary> Creates a new <see cref="T:System.Windows.Media.Media3D.Rect3D" />. </summary>
    Rect3D() : m_x(0.0f), m_y(0.0f), m_z(0.0f), m_sizeX(0.0f), m_sizeY(0.0f), m_sizeZ(0.0f) { };

    /// <summary> Creates a new <see cref="T:System.Windows.Media.Media3D.Rect3D" />. </summary>
    /// <param name="location">Location of the new <see cref="T:System.Windows.Media.Media3D.Rect3D" />.</param>
    /// <param name="size">Size of the new <see cref="T:System.Windows.Media.Media3D.Rect3D" />.</param>
    Rect3D(const Point3D& location, const Size3D& size);

    /// <summary> Creates a new <see cref="T:System.Windows.Media.Media3D.Rect3D" />. </summary>
    /// <param name="x">X-axis coordinate of the new <see cref="T:System.Windows.Media.Media3D.Rect3D" />.</param>
    /// <param name="y">Y-axis coordinate of the new <see cref="T:System.Windows.Media.Media3D.Rect3D" />.</param>
    /// <param name="z">Z-axis coordinate of the new <see cref="T:System.Windows.Media.Media3D.Rect3D" />.</param>
    /// <param name="sizeX">Size of the new <see cref="T:System.Windows.Media.Media3D.Rect3D" /> in the X dimension.</param>
    /// <param name="sizeY">Size of the new <see cref="T:System.Windows.Media.Media3D.Rect3D" /> in the Y dimension.</param>
    /// <param name="sizeZ">Size of the new <see cref="T:System.Windows.Media.Media3D.Rect3D" /> in the Z dimension.</param>
    Rect3D(float x, float y, float z, float sizeX, float sizeY, float sizeZ);

    /// <summary> Gets a value that indicates whether a specified <see cref="T:System.Windows.Media.Media3D.Point3D" /> is within the <see cref="T:System.Windows.Media.Media3D.Rect3D" />, including its edges. </summary>
    /// <returns>True if the specified point or rectangle is within the <see cref="T:System.Windows.Media.Media3D.Rect3D" />, including its edges; false otherwise.</returns>
    /// <param name="point">Point to be tested.</param>
    bool Contains(const Point3D& point);

    /// <summary> Gets a value that indicates whether a specified <see cref="T:System.Windows.Media.Media3D.Point3D" /> is within the <see cref="T:System.Windows.Media.Media3D.Rect3D" />, including its edges. </summary>
    /// <returns>True if the specified point or rectangle is within the <see cref="T:System.Windows.Media.Media3D.Rect3D" />, including its edges; false otherwise.</returns>
    /// <param name="rect">
    /// <see cref="T:System.Windows.Media.Media3D.Rect3D" /> to be tested. </param>
    bool Contains(const Rect3D& rect);

    /// <summary> Gets a value that indicates whether a specified <see cref="T:System.Windows.Media.Media3D.Point3D" /> is within the <see cref="T:System.Windows.Media.Media3D.Rect3D" />, including its edges. </summary>
    /// <returns>True if the specified point or rectangle is within the <see cref="T:System.Windows.Media.Media3D.Rect3D" />, including its edges; false otherwise.</returns>
    /// <param name="x">X-axis coordinate of the <see cref="T:System.Windows.Media.Media3D.Point3D" /> to be tested.</param>
    /// <param name="y">Y-axis coordinate of the <see cref="T:System.Windows.Media.Media3D.Point3D" /> to be tested.</param>
    /// <param name="z">Z-coordinate of the <see cref="T:System.Windows.Media.Media3D.Point3D" /> to be tested.</param>
    bool Contains(float x, float y, float z);

    /// <summary>
    /// <see cref="T:System.Windows.Media.Media3D.Rect3D" /> that is the intersection of the current and specified rectangles. </summary>
    /// <returns />
    /// <param name="rect">The <see cref="T:System.Windows.Media.Media3D.Rect3D" /> to intersect with the current <see cref="T:System.Windows.Media.Media3D.Rect3D" />.</param>
    void Intersect(const Rect3D& rect);

    /// <summary>
    /// <see cref="T:System.Windows.Media.Media3D.Rect3D" /> that is the intersection of the two specified rectangles. </summary>
    /// <returns>Result of the intersection of rect1 and rect2.</returns>
    /// <param name="rect1">First <see cref="T:System.Windows.Media.Media3D.Rect3D" />.</param>
    /// <param name="rect2">Second <see cref="T:System.Windows.Media.Media3D.Rect3D" />.</param>
    static Rect3D Intersect(const Rect3D& rect1, const Rect3D& rect2);

    /// <summary>Returns a value that indicates whether the specified rectangle intersects with this rectangle. </summary>
    /// <returns>True if the specified rectangle intersects with this rectangle; false otherwise.</returns>
    /// <param name="rect">Rectangle to evaluate.</param>
    bool IntersectsWith(const Rect3D& rect);

    /// <summary>Sets the offset translation of the <see cref="T:System.Windows.Media.Media3D.Rect3D" /> to the provided value, specified as a <see cref="T:System.Windows.Media.Media3D.Vector3D" />. </summary>
    /// <returns />
    /// <param name="offsetVector">
    /// <see cref="T:System.Windows.Media.Media3D.Vector3D" /> that specifies the offset translation.</param>
    void Offset(const Vector3D& offsetVector);

    /// <summary>Gets or sets an offset value by which the location of a <see cref="T:System.Windows.Media.Media3D.Rect3D" /> is translated. </summary>
    /// <returns>Rect3D that represents the result of the offset.</returns>
    /// <param name="rect">Rect3D to be translated.</param>
    /// <param name="offsetVector">Vector3D that specifies the offset translation.</param>
    static Rect3D Offset(const Rect3D& rect, const Vector3D& offsetVector);

    /// <summary> Gets or sets an offset value by which the location of a <see cref="T:System.Windows.Media.Media3D.Rect3D" /> is translated. </summary>
    /// <returns>Rect3D that represents the result of the offset.</returns>
    /// <param name="offsetX">Offset along the X axis.</param>
    /// <param name="offsetY">Offset along the Y axis.</param>
    /// <param name="offsetZ">Offset along the Z axis.</param>
    void Offset(float offsetX, float offsetY, float offsetZ);

    /// <summary> Gets or sets an offset value by which the location of a <see cref="T:System.Windows.Media.Media3D.Rect3D" /> is translated. </summary>
    /// <returns>Rect3D that represents the result of the offset.</returns>
    /// <param name="rect">Rect3D to be translated.</param>
    /// <param name="offsetX">Offset along the X axis.</param>
    /// <param name="offsetY">Offset along the Y axis.</param>
    /// <param name="offsetZ">Offset along the Z axis.</param>
    static Rect3D Offset(const Rect3D& rect, float offsetX, float offsetY, float offsetZ);

    /// <summary>Updates a specified <see cref="T:System.Windows.Media.Media3D.Rect3D" /> to reflect the union of that <see cref="T:System.Windows.Media.Media3D.Rect3D" /> and a specified <see cref="T:System.Windows.Media.Media3D.Point3D" />. </summary>
    /// <returns>
    /// <see cref="T:System.Windows.Media.Media3D.Rect3D" /> that represents the result of the union.</returns>
    /// <param name="point">The <see cref="T:System.Windows.Media.Media3D.Point3D" /> whose union with the specified <see cref="T:System.Windows.Media.Media3D.Rect3D" /> is to be evaluated.</param>
    void Union(const Point3D& point);

    /// <summary>Updates a specified <see cref="T:System.Windows.Media.Media3D.Rect3D" /> to reflect the union of that <see cref="T:System.Windows.Media.Media3D.Rect3D" /> and a second specified <see cref="T:System.Windows.Media.Media3D.Rect3D" />. </summary>
    /// <returns>Rect3D that represents the result of the union.</returns>
    /// <param name="rect">The <see cref="T:System.Windows.Media.Media3D.Rect3D" /> whose union with the current <see cref="T:System.Windows.Media.Media3D.Rect3D" /> is to be evaluated.</param>
    void Union(const Rect3D& rect);

    /// <summary>Returns a new <see cref="T:System.Windows.Media.Media3D.Rect3D" /> that represents the union of a <see cref="T:System.Windows.Media.Media3D.Rect3D" />, and a specified <see cref="T:System.Windows.Media.Media3D.Point3D" />.</summary>
    /// <returns>Result of the union of <paramref name="rect" /> and <paramref name="point" />.</returns>
    /// <param name="rect">The <see cref="T:System.Windows.Media.Media3D.Rect3D" /> whose union with the current <see cref="T:System.Windows.Media.Media3D.Rect3D" /> is to be evaluated.</param>
    /// <param name="point">The <see cref="T:System.Windows.Media.Media3D.Point3D" /> whose union with the specified <see cref="T:System.Windows.Media.Media3D.Rect3D" /> is to be evaluated.</param>
    static Rect3D Union(const Rect3D& rect, const Point3D& point);

    /// <summary>Returns a new instance of <see cref="T:System.Windows.Media.Media3D.Rect3D" /> that represents the union of two <see cref="T:System.Windows.Media.Media3D.Rect3D" /> objects. </summary>
    /// <returns>
    /// <see cref="T:System.Windows.Media.Media3D.Rect3D" /> that represents the result of the union of <paramref name="rect1" /> and <paramref name="rect2" />.</returns>
    /// <param name="rect1">First <see cref="T:System.Windows.Media.Media3D.Rect3D" />.</param>
    /// <param name="rect2">Second <see cref="T:System.Windows.Media.Media3D.Rect3D" />.</param>
    static Rect3D Union(const Rect3D& rect1, const Rect3D& rect2);

#pragma endregion Public Methods

#pragma region Public Properties

    /// <summary>Gets an empty Rect3D. </summary>
    /// <returns>Empty Rect3D.</returns>
    static Rect3D get_Empty();

    /// <summary>Gets a value that indicates whether this Rect3D is the Empty rectangle. </summary>
    /// <returns>True if this Rect3D is the empty rectangle; false otherwise.</returns>
    bool get_IsEmpty() const;

    /// <summary>Gets or sets a <see cref="T:System.Windows.Media.Media3D.Point3D" /> that represents the origin of the Rect3D. </summary>
    /// <returns>
    /// <see cref="T:System.Windows.Media.Media3D.Point3D" /> that represents the origin of the Rect3D, typically the back bottom left corner.  The default value is (0,0,0).</returns>
    Point3D get_Location() const;
    void set_Location(const Point3D& value);
    IMPLEMENT_VALUE_PROPERTY(Location, Point3D, false);

    /// <summary>Gets or sets the area of the Rect3D. </summary>
    /// <returns>
    /// <see cref="T:System.Windows.Media.Media3D.Size3D" /> that specifies the area of the Rect3D.</returns>
    Size3D get_Size() const;
    void set_Size(const Size3D& value);
    IMPLEMENT_VALUE_PROPERTY(Size, Size3D, false);

    /// <summary>Gets or sets the size of the Rect3D in the X dimension. </summary>
    /// <returns>Double that specifies the size of the rectangle in the X dimension.</returns>
    float get_SizeX() const { return m_sizeX; }
    void set_SizeX(float value);
    IMPLEMENT_VALUE_PROPERTY(SizeX, float, false);

    /// <summary>Gets or sets the size of the Rect3D in the Y dimension. </summary>
    /// <returns>Double that specifies the size of the rectangle in the Y dimension.</returns>
    float get_SizeY() const { return m_sizeY; }
    void set_SizeY(float value);
    IMPLEMENT_VALUE_PROPERTY(SizeY, float, false);

    /// <summary>Gets or sets the size of the Rect3D in the Z dimension. </summary>
    /// <returns>Double that specifies the size of the rectangle in the Z dimension.</returns>
    float get_SizeZ() const { return m_sizeZ; }
    void set_SizeZ(float value);
    IMPLEMENT_VALUE_PROPERTY(SizeZ, float, false);

    /// <summary>Gets or sets the value of the X coordinate of the rectangle. </summary>
    /// <returns>Value of the X coordinate of the rectangle.</returns>
    float get_X() const { return m_x; }
    void set_X(float value);
    IMPLEMENT_VALUE_PROPERTY(X, float, false);

    /// <summary>Gets or sets the value of the Y coordinate of the rectangle. </summary>
    /// <returns>Value of the Y coordinate of the rectangle.</returns>
    float get_Y() const { return m_y; }
    void set_Y(float value);
    IMPLEMENT_VALUE_PROPERTY(Y, float, false);
 
    /// <summary>Gets or sets the value of the Z coordinate of the rectangle. </summary>
    /// <returns>Value of the Z coordinate of the rectangle.</returns>
    float get_Z() const { return m_z; }
    void set_Z(float value);
    IMPLEMENT_VALUE_PROPERTY(Z, float, false);

#pragma endregion Public Properties

public:

#pragma region Internal Methods

    Rect3D(const Point3D& point1, const Point3D& point2);
    Rect3D(const Point3D& point, const Vector3D& vector);

#pragma endregion Internal Methods

private:

#pragma region Private Methods 

    bool ContainsInternal(float x, float y, float z);
    static Rect3D CreateEmptyRect3D();

#pragma endregion Private Methods

#pragma region Private Fields

    float m_sizeX;
    float m_sizeY;
    float m_sizeZ;
    float m_x;
    float m_y;
    float m_z;

#pragma endregion Private Fields

};


}; // namespace AVUI

